"""
Set of objects to manage triggers streams.

A trigger is an audio signal with a value of 1 surrounded by 0s.

TrigXXX objects use this kind of signal to generate different 
processes with sampling rate time accuracy.

"""

"""
Copyright 2010 Olivier Belanger

This file is part of pyo, a python module to help digital signal
processing script creation.

pyo is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

pyo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with pyo.  If not, see <http://www.gnu.org/licenses/>.
"""
import sys
from _core import *
from _maps import *
from _widgets import createGraphWindow
from types import SliceType, ListType, TupleType

class Trig(PyoObject):
    """
    Sends one trigger.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    Trig sends a trigger each time it's play() method is called.

    Parentclass: PyoObject

    Parameters:

    Methods:

    Attributes:

    Notes:

    The out() method is bypassed. Trig's signal can not be sent to audio outs.

    Trig has no `mul` and `add` attributes.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> a = Trig()
    >>> env = HannTable()
    >>> tenv = TrigEnv(a, table=env, dur=5, mul=.3)
    >>> n = Noise(tenv).out()

    """
    def __init__(self):
        PyoObject.__init__(self)
        self._base_objs = [Trig_base()]

    def __dir__(self):
        return []

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

class Metro(PyoObject):
    """
    Generates isochronous trigger signals.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    The play() method starts the metro and is not called at the object 
    creation time.

    Parentclass: PyoObject

    Parameters:

    time : float or PyoObject, optional
        Time between each trigger in seconds. Defaults to 1.
    poly : int, optional
        Metronome polyphony. Denotes how many independent streams are 
        generated by the metronome, allowing overlapping processes.
        Available only at initialization. Defaults to 1.

    Methods:

    setTime(x) : Replace the `time` attribute.

    Attributes:

    time : float or PyoObject. Time between each trigger in seconds.

    Notes:

    The out() method is bypassed. Metro's signal can not be sent to audio outs.

    Metro has no `mul` and `add` attributes.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(time=.125, poly=2).play()
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> freq = TrigRand(met, min=400, max=1000)
    >>> a = Sine(freq=freq, mul=amp).out()

    """
    def __init__(self, time=1, poly=1):
        PyoObject.__init__(self)
        self._time = time
        self._poly = poly
        time, lmax = convertArgsToLists(time)
        self._base_objs = [Metro_base(wrap(time,i)*poly, (float(j)/poly)) for i in range(lmax) for j in range(poly)]

    def __dir__(self):
        return ['time']

    def setTime(self, x):
        """
        Replace the `time` attribute.
        
        Parameters:
        
        x : float or PyoObject
            New `time` attribute.
        
        """
        self._time = x
        x, lmax = convertArgsToLists(x)
        [obj.setTime(wrap(x,i)*self._poly) for i, obj in enumerate(self._base_objs)]

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)
        
    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.001, 1., 'log', 'time', self._time)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)
         
    @property
    def time(self):
        """float or PyoObject. Time between each trigger in seconds.""" 
        return self._time
    @time.setter
    def time(self, x): self.setTime(x)

class Seq(PyoObject):
    """
    Generates a rhythmic sequence of trigger signals.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    The play() method starts the sequence and is not called at the object 
    creation time.

    Parentclass: PyoObject

    Parameters:

    time : float or PyoObject, optional
        Base time between each trigger in seconds. Defaults to 1.
    seq : list of ints, optional
        Sequence of beat durations in time's unit. Defaults to [1].
    poly : int, optional
        Seq polyphony. Denotes how many independent streams are
        generated by the metronome, allowing overlapping processes.
        Available only at initialization. Defaults to 1.

    Methods:

    setTime(x) : Replace the `time` attribute.
    setSeq(x) ; Replace the `seq` attribute.

    Attributes:

    time : float or PyoObject. Base time between each trigger in seconds.
    seq : list of ints. Sequence of beat durations in time's unit.

    Notes:

    The out() method is bypassed. Seq's signal can not be sent to audio outs.

    Seq has no `mul` and `add` attributes.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> env = CosTable([(0,0),(300,1),(1000,.3),(8191,0)])
    >>> seq = Seq(time=.125, seq=[2,1,1,2], poly=2).play()
    >>> tr = TrigRand(seq, min=250, max=500, port=.005)
    >>> amp = TrigEnv(seq, table=env, dur=.25, mul=.25)
    >>> a = SineLoop(tr, feedback=0.07, mul=amp).out()

    """
    def __init__(self, time=1, seq=[1], poly=1):
        PyoObject.__init__(self)
        if type(seq) != ListType:
            print >> sys.stderr, 'TypeError: "seq" argument of %s must be a list.\n' % self.__class__.__name__
            exit()
        self._time = time
        self._seq = seq
        self._poly = poly
        time, lmax = convertArgsToLists(time)
        if type(seq[0]) != ListType:
            self._base_players = [Seqer_base(wrap(time,i), seq, poly) for i in range(lmax)]
        else:
            seqlen = len(seq)
            lmax = max(seqlen, lmax)
            self._base_players = [Seqer_base(wrap(time,i), wrap(seq,i), poly) for i in range(lmax)]            
        self._base_objs = [Seq_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]

    def __dir__(self):
        return ['time', 'seq']

    def setTime(self, x):
        """
        Replace the `time` attribute.

        Parameters:

        x : float or PyoObject
            New `time` attribute.

        """
        self._time = x
        x, lmax = convertArgsToLists(x)
        [obj.setTime(wrap(x,i)) for i, obj in enumerate(self._base_players)]

    def setSeq(self, x):
        """
        Replace the `seq` attribute.

        Parameters:

        x : list of ints
            New `seq` attribute.

        """
        self._seq = x
        if type(x[0]) != ListType:
            [obj.setSeq(x) for i, obj in enumerate(self._base_players)]
        else:
            [obj.setSeq(wrap(x,i)) for i, obj in enumerate(self._base_players)]

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.001, 10., 'log', 'time', self._time)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def time(self):
        """float or PyoObject. Base time between each trigger in seconds.""" 
        return self._time
    @time.setter
    def time(self, x): self.setTime(x)

    @property
    def seq(self):
        """List of ints. Sequence of beat durations in time's unit.""" 
        return self._seq
    @seq.setter
    def seq(self, x): self.setSeq(x)

class Cloud(PyoObject):
    """
    Generates random triggers.

    Generates random triggers with control over the generation density.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    The play() method starts the Cloud and is not called at the object 
    creation time.

    Parentclass: PyoObject

    Parameters:

    density : float or PyoObject, optional
        Average number of triggers per second. Defaults to 10.
    poly : int, optional
        Cloud polyphony. Denotes how many independent streams are 
        generated by the object, allowing overlapping processes.
        Available only at initialization. Defaults to 1.

    Methods:

    setDensity(x) : Replace the `density` attribute.

    Attributes:

    density : float or PyoObject. Average number of triggers per second.

    Notes:

    The out() method is bypassed. Cloud's signal can not be sent to audio outs.

    Cloud has no `mul` and `add` attributes.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> dens = Expseg([(0,1),(5,50)], loop=True, exp=5, initToFirstVal=True).play()
    >>> m = Cloud(density=dens, poly=2).play()
    >>> tr = TrigRand(m, min=300, max=1000)
    >>> tr_p = Port(tr, risetime=0.001, falltime=0.001)
    >>> a = Sine(freq=tr, mul=0.2).out()

    """
    def __init__(self, density=10, poly=1):
        PyoObject.__init__(self)
        self._density = density
        self._poly = poly
        density, lmax = convertArgsToLists(density)
        self._base_players = [Clouder_base(wrap(density,i), poly) for i in range(lmax)]
        self._base_objs = [Cloud_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]

    def __dir__(self):
        return ['density']

    def setDensity(self, x):
        """
        Replace the `density` attribute.
        
        Parameters:
        
        x : float or PyoObject
            New `density` attribute.
        
        """
        self._density = x
        x, lmax = convertArgsToLists(x)
        [obj.setDensity(wrap(x,i)) for i, obj in enumerate(self._base_players)]
       
    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)
        
    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0, 100., 'lin', 'density', self._density)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)
         
    @property
    def density(self):
        """float or PyoObject. Average density of triggers generation.""" 
        return self._density
    @density.setter
    def density(self, x): self.setDensity(x)

class Beat(PyoObject):
    """
    Generates algorithmic trigger patterns.
    
    A trigger is an audio signal with a value of 1 surrounded by 0s.

    Beat generates measures of length `taps` and uses weight parameters
    (`w1`, `w2` and `w3`) to compute the chances of a beat to be present
    in the generated measure.

    User can store the current pattern in one of the 32 preset slots with
    the store() method and recall it later with recall(x).
    
    A preset is a list where the first value is the number of beats in the
    measure, followed by 1s and 0s. For a 4/4 measure with only down beats:
    
    [16, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0] 
    
    The play() method starts the Beat and is not called at the object 
    creation time.

    Parentclass: PyoObject

    Parameters:

    time : float or PyoObject, optional
        Time, in seconds, between each beat of the pattern. Defaults to 0.125.
    taps : int, optional
        Number of beats in the generated pattern, max = 64. Defaults to 16.
    w1 : int {0 -> 100}, optional
        Probability for down beats. Defaults to 80.
    w2 : int {0 -> 100}, optional
        Probability for up beats. Defaults to 50.
    w3 : int {0 -> 100}, optional
        Probability for the weakest beats. Defaults to 30.
    poly : int, optional
        Beat polyphony. Denotes how many independent streams are 
        generated by the object, allowing overlapping processes.
        Available only at initialization. Defaults to 1.

    Methods:

    setTime(x) : Replace the `time` attribute.
    setTaps(x) : Replace the `taps` attribute.
    setW1(x) : Replace the `w1` attribute.
    setW2(x) : Replace the `w2` attribute.
    setW3(x) : Replace the `w3` attribute.
    setWeights(w1, w2, w3) : Replace the weight attributes.
    new() : Generates a new pattern with the current parameters.
    fill() : Generates a fill-in pattern and then restore the current one.
    store(x) : Store the current pattern in memory `x`.
    recall(x) : Recall the pattern previously stored in memory `x`.
    getPresets() : Returns the list of stored presets.
    setPresets(list) : Store a list of presets.
    get(identifier, all) : Return the first sample of the current 
        buffer as a float.
     
    Attributes:

    time : float or PyoObject. Time, in seconds, between each tap of the pattern.
    taps : int. Number of taps in the generated pattern.
    w1 : Probability for down beats.
    w2 : Probability for up beats.
    w3 : Probability for other beats.
    
    Notes:

    Beat outputs many signals identified with a string between brackets:
    
    obj['tap'] returns audio stream of the current tap of the measure.
    obj['amp'] returns audio stream of the current beat amplitude.
    obj['dur'] returns audio stream of the current beat duration in seconds.
    obj['end'] returns audio stream with a trigger just before the end of the measure.
    
    obj without brackets returns the generated trigger stream of the measure.
     
    The out() method is bypassed. Beat's signal can not be sent to audio outs.

    Beat has no `mul` and `add` attributes.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> beat = Beat(time=.125, taps=16, w1=[90,80], w2=50, w3=35, poly=1).play()
    >>> trmid = TrigXnoiseMidi(beat, dist=12, mrange=(60, 96))
    >>> trhz = Snap(trmid, choice=[0,2,3,5,7,8,10], scale=1)
    >>> tr2 = TrigEnv(beat, table=t, dur=beat['dur'], mul=beat['amp'])
    >>> a = Sine(freq=trhz, mul=tr2*0.3).out()

    """
    def __init__(self, time=.125, taps=16, w1=80, w2=50, w3=30, poly=1):
        PyoObject.__init__(self)
        self._tap_dummy = []
        self._amp_dummy = []
        self._dur_dummy = []
        self._end_dummy = []
        self._time = time
        self._taps = taps
        self._w1 = w1
        self._w2 = w2
        self._w3 = w3
        self._poly = poly
        time, taps, w1, w2, w3, lmax = convertArgsToLists(time, taps, w1, w2, w3)
        self._base_players = [Beater_base(wrap(time,i), wrap(taps,i), wrap(w1,i), wrap(w2,i), wrap(w3,i), poly) for i in range(lmax)]
        self._base_objs = [Beat_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
        self._tap_objs = [BeatTapStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
        self._amp_objs = [BeatAmpStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
        self._dur_objs = [BeatDurStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
        self._end_objs = [BeatEndStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]

    def __dir__(self):
        return ['time', 'taps', 'w1', 'w2', 'w3']

    def __getitem__(self, i):
        if i == 'tap':
            self._tap_dummy.append(Dummy([obj for obj in self._tap_objs]))
            return self._tap_dummy[-1]
        if i == 'amp':
            self._amp_dummy.append(Dummy([obj for obj in self._amp_objs]))
            return self._amp_dummy[-1]
        if i == 'dur':
            self._dur_dummy.append(Dummy([obj for obj in self._dur_objs]))
            return self._dur_dummy[-1]
        if i == 'end':
            self._end_dummy.append(Dummy([obj for obj in self._end_objs]))
            return self._end_dummy[-1]
        if type(i) == SliceType:
            return self._base_objs[i]
        if i < len(self._base_objs):
            return self._base_objs[i]
        else:
            print "'i' too large!"         

    def get(self, identifier="amp", all=False):
        """
        Return the first sample of the current buffer as a float.

        Can be used to convert audio stream to usable Python data.

        "tap", "amp" or "dur" must be given to `identifier` to specify
        which stream to get value from.

        Parameters:

            identifier : string {"tap", "amp", "dur"}
                Address string parameter identifying audio stream.
                Defaults to "amp".
            all : boolean, optional
                If True, the first value of each object's stream
                will be returned as a list. Otherwise, only the value
                of the first object's stream will be returned as a float.
                Defaults to False.

        """
        if not all:
            return self.__getitem__(identifier)[0]._getStream().getValue()
        else:
            return [obj._getStream().getValue() for obj in self.__getitem__(identifier).getBaseObjects()]

    def new(self):
        """
        Generates a new pattern with the current parameters.
        
        """
        [obj.new() for i, obj in enumerate(self._base_players)]

    def fill(self):
        """
        Generates a fill-in pattern and then restore the current one.

        """
        [obj.fill() for i, obj in enumerate(self._base_players)]

    def store(self, x):
        """
        Store the current pattern in memory `x`.
        
        Parameters:
        
        x : int
            Memory number. 0 <= x < 32.

        """
        [obj.store(x) for i, obj in enumerate(self._base_players)]

    def recall(self, x):
        """
        Recall the pattern previously stored in memory `x`.

        Parameters:

        x : int
            Memory number. 0 <= x < 32.

        """
        [obj.recall(x) for i, obj in enumerate(self._base_players)]
        
    def getPresets(self):
        """
        Returns the list of stored presets.

        """
        if len(self._base_players) == 1:
            return self._base_players[0].getPresets()
        else:    
            return [obj.getPresets() for obj in self._base_players]

    def setPresets(self, x):
        """
        Store a list presets.
        
        Parameters:
        
        x : list
            List of presets.

        """
        if len(self._base_players) == 1:
            return self._base_players[0].setPresets(x)
        else:    
            return [obj.setPresets(x[i]) for i, obj in enumerate(self._base_players)]

    def setTime(self, x):
        """
        Replace the `time` attribute.

        Parameters:

        x : float or PyoObject
            New `time` attribute.

        """
        self._time = x
        x, lmax = convertArgsToLists(x)
        [obj.setTime(wrap(x,i)) for i, obj in enumerate(self._base_players)]

    def setTaps(self, x):
        """
        Replace the `taps` attribute.

        Parameters:

        x : int
            New `taps` attribute.

        """
        self._taps = x
        x, lmax = convertArgsToLists(x)
        [obj.setTaps(wrap(x,i)) for i, obj in enumerate(self._base_players)]

    def setW1(self, x):
        """
        Replace the `w1` attribute.

        Parameters:

        x : int
            New `w1` attribute.

        """
        self.setWeights(w1=x)

    def setW2(self, x):
        """
        Replace the `w2` attribute.

        Parameters:

        x : int
            New `w2` attribute.

        """
        self.setWeights(w2=x)

    def setW3(self, x):
        """
        Replace the `w3` attribute.

        Parameters:

        x : int
            New `w3` attribute.

        """
        self.setWeights(w3=x)
        
    def setWeights(self, w1=None, w2=None, w3=None):
        """
        Replace the weight attributes.
        
        Arguments set to `None` remain unchanged.

        Parameters:

        w1 : int, optional
            New `w1` attribute. Defaults to None.
        w2 : int, optional
            New `w2` attribute. Defaults to None.
        w3 : int, optional
            New `w3` attribute. Defaults to None.

        """
        if w1 != None: self._w1 = w1
        if w2 != None: self._w2 = w2
        if w3 != None: self._w3 = w3
        w1, w2, w3, lmax = convertArgsToLists(w1, w2, w3)
        [obj.setWeights(wrap(w1,i), wrap(w2,i), wrap(w3,i)) for i, obj in enumerate(self._base_players)]

    def play(self, dur=0, delay=0):
        dur, delay, lmax = convertArgsToLists(dur, delay)
        self._tap_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._tap_objs)]
        self._amp_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._amp_objs)]
        self._dur_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._dur_objs)]
        self._end_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._end_objs)]
        return PyoObject.play(self, dur, delay)

    def stop(self):
        [obj.stop() for obj in self._tap_objs]
        [obj.stop() for obj in self._amp_objs]
        [obj.stop() for obj in self._dur_objs]
        [obj.stop() for obj in self._end_objs]
        return PyoObject.stop(self)

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.001, 1., 'lin', 'time', self._time)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def time(self):
        """float or PyoObject. Time, in seconds, between each beat.""" 
        return self._time
    @time.setter
    def time(self, x): self.setTime(x)

    @property
    def taps(self):
        """int. Number of beats in the generated pattern.""" 
        return self._taps
    @taps.setter
    def taps(self, x): self.setTaps(x)

    @property
    def w1(self):
        """int. Probability for down beats.""" 
        return self._w1
    @w1.setter
    def w1(self, x): self.setW1(x)

    @property
    def w2(self):
        """int. Probability for up beats.""" 
        return self._w2
    @w2.setter
    def w2(self, x): self.setW2(x)

    @property
    def w3(self):
        """int. Probability for other beats.""" 
        return self._w3
    @w3.setter
    def w3(self, x): self.setW3(x)

class TrigRandInt(PyoObject):
    """
    Pseudo-random integer generator.

    TrigRandInt generates a pseudo-random number integer number between 
    0 and `max` values each time it receives a trigger in its `input` 
    parameter. The value is kept until the next trigger.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    max : float or PyoObject, optional
        Maximum value for the random generation. Defaults to 100.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setMax(x) : Replace the `max` attribute.

    Attributes:

    input : PyoObject. Audio trigger signal.
    max : float or PyoObject. Maximum value.

    Notes:

    The out() method is bypassed. TrigRandInt's signal can not be sent 
    to audio outs.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(.125, poly=2).play()
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> tr = TrigRandInt(met, max=10, mul=100, add=200)
    >>> a = Sine(tr, mul=amp).out()

    """
    def __init__(self, input, max=100., mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._max = max
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, max, mul, add, lmax = convertArgsToLists(self._in_fader, max, mul, add)
        self._base_objs = [TrigRandInt_base(wrap(in_fader,i), wrap(max,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'max', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setMax(self, x):
        """
        Replace the `max` attribute.

        Parameters:

        x : float or PyoObject
            new `max` attribute.

        """
        self._max = x
        x, lmax = convertArgsToLists(x)
        [obj.setMax(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(1., 200., 'lin', 'max', self._max),
                          SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def max(self): return self._max
    @max.setter
    def max(self, x): self.setMax(x)

class TrigRand(PyoObject):
    """
    Pseudo-random number generator.

    TrigRand generates a pseudo-random number between `min` and `max` 
    values each time it receives a trigger in its `input` parameter. 
    The value is kept until the next trigger.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    min : float or PyoObject, optional
        Minimum value for the random generation. Defaults to 0.
    max : float or PyoObject, optional
        Maximum value for the random generation. Defaults to 1.
    port : float, optional
        Portamento. Time to reach a new value. Defaults to 0.
    init : float, optional
        Initial value. Available at initialization time only. 
        Defaults to 0.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setMin(x) : Replace the `min` attribute.
    setMax(x) : Replace the `max` attribute.
    setPort(x) : Replace the `port` attribute.

    Attributes:

    input : PyoObject. Audio trigger signal.
    min : float or PyoObject. Minimum value.
    max : float or PyoObject. Maximum value.
    port : float. Ramp time.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(.125, poly=2).play()
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> tr = TrigRand(met, 400, 600)
    >>> a = Sine(tr, mul=amp).out()

    """
    def __init__(self, input, min=0., max=1., port=0., init=0., mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._min = min
        self._max = max
        self._port = port
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, min, max, port, init, mul, add, lmax = convertArgsToLists(self._in_fader, min, max, port, init, mul, add)
        self._base_objs = [TrigRand_base(wrap(in_fader,i), wrap(min,i), wrap(max,i), wrap(port,i), wrap(init,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'min', 'max', 'port', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setMin(self, x):
        """
        Replace the `min` attribute.
        
        Parameters:

        x : float or PyoObject
            new `min` attribute.
        
        """
        self._min = x
        x, lmax = convertArgsToLists(x)
        [obj.setMin(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setMax(self, x):
        """
        Replace the `max` attribute.
        
        Parameters:

        x : float or PyoObject
            new `max` attribute.
        
        """
        self._max = x
        x, lmax = convertArgsToLists(x)
        [obj.setMax(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setPort(self, x):
        """
        Replace the `port` attribute.
        
        Parameters:

        x : float
            new `port` attribute.
        
        """
        self._port = x
        x, lmax = convertArgsToLists(x)
        [obj.setPort(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0., 1., 'lin', 'min', self._min),
                          SLMap(1., 2., 'lin', 'max', self._max),
                          SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def min(self): return self._min
    @min.setter
    def min(self, x): self.setMin(x)
    @property
    def max(self): return self._max
    @max.setter
    def max(self, x): self.setMax(x)
    @property
    def port(self): return self._port
    @port.setter
    def port(self, x): self.setPort(x)

class TrigChoice(PyoObject):
    """
    Random generator from user's defined values.

    TrigChoice chooses randomly a new value in list `choice` each 
    time it receives a trigger in its `input` parameter. The value 
    is kept until the next trigger.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    choice : list of floats
        Possible values for the random generation.
    port : float, optional
        Portamento. Time to reach a new value. Defaults to 0.
    init : float, optional
        Initial value. Available at initialization time only. 
        Defaults to 0.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setChoice(x) : Replace the `choice` attribute.
    setPort(x) : Replace the `port` attribute.

    Attributes:

    input : PyoObject. Audio trigger signal.
    choice : list of floats. Possible values.
    port : float. Ramp time.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(.125, poly=2).play()
    >>> freq = TrigChoice(met, [300, 350, 400, 450, 500, 550])
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> a = Sine(freq=freq, mul=amp).out()

    """
    def __init__(self, input, choice, port=0., init=0., mul=1, add=0):
        PyoObject.__init__(self)
        if type(choice) != ListType:
            print >> sys.stderr, 'TypeError: "choice" argument of %s must be a list.\n' % self.__class__.__name__
            exit()
        self._input = input
        self._choice = choice
        self._port = port
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, port, init, mul, add, lmax = convertArgsToLists(self._in_fader, port, init, mul, add)
        if type(choice[0]) != ListType:
            self._base_objs = [TrigChoice_base(wrap(in_fader,i), choice, wrap(port,i), wrap(init,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
        else:
            choicelen = len(choice)
            lmax = max(choicelen, lmax)
            self._base_objs = [TrigChoice_base(wrap(in_fader,i), wrap(choice,i), wrap(port,i), wrap(init,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'choice', 'port', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setChoice(self, x):
        """
        Replace the `choice` attribute.
        
        Parameters:

        x : list of floats
            new `choice` attribute.
        
        """
        self._choice = x
        if type(x[0]) != ListType:
            [obj.setChoice(self._choice) for i, obj in enumerate(self._base_objs)]
        else:
            [obj.setChoice(wrap(self._choice,i)) for i, obj in enumerate(self._base_objs)]

    def setPort(self, x):
        """
        Replace the `port` attribute.
        
        Parameters:

        x : float
            new `port` attribute.
        
        """
        self._port = x
        x, lmax = convertArgsToLists(x)
        [obj.setPort(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def choice(self): return self._choice
    @choice.setter
    def choice(self, x): self.setChoice(x)
    @property
    def port(self): return self._port
    @port.setter
    def port(self, x): self.setPort(x)

class TrigFunc(PyoObject):
    """
    Python function callback.

    TrigFunc calls the function given at parameter `function` each 
    time it receives a trigger in its `input` parameter.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    function : Python function
        Function to be called.
    arg : anything, optional
        Argument sent to the function's call. If None, the function
        will be called without argument. Defaults to None.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setFunction(x) : Replace the `function` attribute.
    setArg(x) : Replace the `arg` attribute.

    Attributes:

    input : PyoObject. Audio trigger signal.
    function : Python function. Function to be called.
    arg : Anything. Function's argument.

    Notes:

    The out() method is bypassed. TrigFunc's signal can not be sent 
    to audio outs.

    TrigFunc has no `mul` and `add` attributes.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> f = Fader(fadein=.005, fadeout=.1, dur=.12, mul=.2)
    >>> a = SineLoop(midiToHz([60,60]), feedback=0.05, mul=f).out()
    >>> c = 0.0
    >>> def count():
    ...     global c
    ...     freq = midiToHz(round(c) + 60)
    ...     a.freq = [freq, freq*0.995]
    ...     c += 1.77
    ...     if c > 13: c = 0
    ...     f.play()
    >>> m = Metro(.125).play()
    >>> tf = TrigFunc(m, count)

    """
    def __init__(self, input, function, arg=None):
        PyoObject.__init__(self)
        if type(function) == ListType or type(function) == TupleType:
            if not callable(function[0]):
                print >> sys.stderr, 'TypeError: "function" argument of %s must be callable.\n' % self.__class__.__name__
                exit()
        else:
            if not callable(function):
                print >> sys.stderr, 'TypeError: "function" argument of %s must be callable.\n' % self.__class__.__name__
                exit()
        self._input = input
        self._function = function
        self._arg = arg
        self._in_fader = InputFader(input)
        in_fader, function, arg, lmax = convertArgsToLists(self._in_fader, function, arg)
        self._base_objs = [TrigFunc_base(wrap(in_fader,i), wrap(function,i), wrap(arg,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'function', 'arg']

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass
        
    def setAdd(self, x):
        pass    

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setFunction(self, x):
        """
        Replace the `function` attribute.
        
        Parameters:

        x : Python function
            new `function` attribute.
        
        """
        self._function = x
        x, lmax = convertArgsToLists(x)
        [obj.setFunction(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setArg(self, x):
        """
        Replace the `arg` attribute.

        Parameters:

        x : Anything
            new `arg` attribute.

        """
        self._arg = x
        x, lmax = convertArgsToLists(x)
        [obj.setArg(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def function(self): return self._function
    @function.setter
    def function(self, x): self.setFunction(x)
    @property
    def arg(self): return self._arg
    @arg.setter
    def arg(self, x): self.setArg(x)
     
class TrigEnv(PyoObject):
    """
    Envelope reader generator.

    TrigEnv starts reading an envelope in `dur` seconds each time it 
    receives a trigger in its `input` parameter.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    table : PyoTableObject
        Table containing the envelope.
    dur : float or PyoObject, optional
        Duration in seconds of the envelope. Defaults to 1.
    interp : int, optional
        Choice of the interpolation method. Defaults to 2.
            1 : no interpolation
            2 : linear
            3 : cosinus
            4 : cubic

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setTable(x) : Replace the `table` attribute.
    setDur(x) : Replace the `dur` attribute.
    setInterp(x) : Replace the `interp` attribute.

    Attributes:

    input : PyoObject. Audio trigger signal.
    table : PyoTableObject. Envelope table.
    dur : float or PyoObject. Duration in seconds.
    interp : int {1, 2, 3, 4}, Interpolation method.

    Notes:

    TrigEnv will sends a trigger signal at the end of the playback. 
    User can retreive the trigger streams by calling obj['trig']. 
    Useful to synchronize other processes. 

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> env = HannTable()
    >>> m = Metro(.125, poly=2).play()
    >>> tr = TrigRand(m, 400, 600)
    >>> te = TrigEnv(m, table=env, dur=.25, mul=.2)
    >>> a = Sine(tr, mul=te).out()

    """
    def __init__(self, input, table, dur=1, interp=2, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._table = table
        self._dur = dur
        self._interp = interp
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, table, dur, interp, mul, add, lmax = convertArgsToLists(self._in_fader, table, dur, interp, mul, add)
        self._base_objs = [TrigEnv_base(wrap(in_fader,i), wrap(table,i), wrap(dur,i), wrap(interp,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
        self._trig_objs = Dummy([TriggerDummy_base(obj) for obj in self._base_objs])

    def __dir__(self):
        return ['input', 'table', 'dur', 'interp', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setTable(self, x):
        """
        Replace the `table` attribute.
        
        Parameters:

        x : PyoTableObject
            new `table` attribute.
        
        """
        self._table = x
        x, lmax = convertArgsToLists(x)
        [obj.setTable(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
        
    def setDur(self, x):
        """
        Replace the `dur` attribute.
        
        Parameters:

        x : float or PyoObject
            new `dur` attribute.
        
        """
        self._dur = x
        x, lmax = convertArgsToLists(x)
        [obj.setDur(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setInterp(self, x):
        """
        Replace the `interp` attribute.
        
        Parameters:

        x : int {1, 2, 3, 4}
            new `interp` attribute.
        
        """
        self._interp = x
        x, lmax = convertArgsToLists(x)
        [obj.setInterp(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.01, 10., 'lin', 'dur', self._dur), SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def table(self): return self._table
    @table.setter
    def table(self, x): self.setTable(x)
    @property
    def dur(self): return self._dur
    @dur.setter
    def dur(self, x): self.setDur(x)
    @property
    def interp(self): return self._interp
    @interp.setter
    def interp(self, x): self.setInterp(x)

class TrigLinseg(PyoObject):
    """
    Line segments trigger.

    TrigLinseg starts reading a break-points line segments each time it 
    receives a trigger in its `input` parameter.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    list : list of tuples
        Points used to construct the line segments. Each tuple is a
        new point in the form (time, value). Times are given in seconds
        and must be in increasing order.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setList(x) : Replace the `list` attribute.
    replace(x) : Alias for `setList` method.
    graph(xlen, yrange, title, wxnoserver) : Opens a grapher window 
        to control the shape of the envelope.

    Attributes:

    input : PyoObject. Audio trigger signal.
    list : list of tuples. Points used to construct the line segments.

    Notes:

    TrigLinseg will sends a trigger signal at the end of the playback. 
    User can retreive the trigger streams by calling obj['trig']. 
    Useful to synchronize other processes. 

    The out() method is bypassed. TrigLinseg's signal can not be sent 
    to audio outs.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> m = Metro(time=1, poly=2).play()
    >>> pit = TrigLinseg(m, [(0,1000),(.1,1300),(.2,900),(.3,1000),(2,1000)])
    >>> a = Sine(pit, mul=.2).out()

    """
    def __init__(self, input, list, mul=1, add=0):
        PyoObject.__init__(self)
        if type(list) != ListType:
            print >> sys.stderr, 'TypeError: "list" argument of %s must be a list of tuples.\n' % self.__class__.__name__
            exit()
        if type(list[0]) != TupleType:
            print >> sys.stderr, 'TypeError: "list" argument of %s must be a list of tuples.\n' % self.__class__.__name__
            exit()
        self._input = input
        self._list = list
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add)
        self._base_objs = [TrigLinseg_base(wrap(in_fader,i), list, wrap(mul,i), wrap(add,i)) for i in range(lmax)]
        self._trig_objs = Dummy([TriggerDummy_base(obj) for obj in self._base_objs])

    def __dir__(self):
        return ['input', 'list', 'mul', 'add']

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setList(self, x):
        """
        Replace the `list` attribute.
        
        Parameters:

        x : list of tuples
            new `list` attribute.
        
        """
        self._list = x
        [obj.setList(x) for i, obj in enumerate(self._base_objs)]

    def replace(self, x):
        """
        Alias for `setList` method.

        Parameters:

        x : list of tuples
            new `list` attribute.

        """
        self.setList(x)

    def getPoints(self):
        return self._list

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    def graph(self, xlen=None, yrange=None, title=None, wxnoserver=False):
        """
        Opens a grapher window to control the shape of the envelope.

        When editing the grapher with the mouse, the new set of points
        will be send to the object on mouse up. 

        Ctrl+C with focus on the grapher will copy the list of points to the 
        clipboard, giving an easy way to insert the new shape in a script.

        Parameters:

        xlen : float, optional
            Set the maximum value of the X axis of the graph. If None, the
            maximum value is retrieve from the current list of points.
            Defaults to None.
        yrange : tuple, optional
            Set the min and max values of the Y axis of the graph. If
            None, min and max are retrieve from the current list of points.
            Defaults to None.
        title : string, optional
            Title of the window. If none is provided, the name of the 
            class is used.
        wxnoserver : boolean, optional
            With wxPython graphical toolkit, if True, tells the 
            interpreter that there will be no server window and not 
            to wait for it before showing the controller window. 
            Defaults to False.

        """
        if xlen == None:
            xlen = float(self._list[-1][0])
        else:
            xlen = float(xlen)
        if yrange == None:
            ymin = float(min([x[1] for x in self._list]))
            ymax = float(max([x[1] for x in self._list]))
            if ymin == ymax:
                yrange = (0, ymax)
            else:
                yrange = (ymin, ymax)
        createGraphWindow(self, 0, xlen, yrange, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def list(self): return self._list
    @list.setter
    def list(self, x): self.setList(x)

class TrigExpseg(PyoObject):
    """
    Exponential segments trigger.

    TrigExpseg starts reading break-points exponential segments each time 
    it receives a trigger in its `input` parameter.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    list : list of tuples
        Points used to construct the line segments. Each tuple is a
        new point in the form (time, value). Times are given in seconds
        and must be in increasing order.
    exp : float, optional
        Exponent factor. Used to control the slope of the curves.
        Defaults to 10.
    inverse : boolean, optional
        If True, downward slope will be inversed. Useful to create 
        biexponential curves. Defaults to True.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setList(x) : Replace the `list` attribute.
    replace(x) : Alias for `setList` method.
    setExp(x) : Replace the `exp` attribute.
    setInverse(x) : Replace the `inverse` attribute.
    graph(xlen, yrange, title, wxnoserver) : Opens a grapher window 
        to control the shape of the envelope.

    Attributes:

    input : PyoObject. Audio trigger signal.
    list : list of tuples. Points used to construct the line segments.
    exp : float. Exponent factor.    
    inverse : boolean. Inversion of downward slope.

    Notes:

    TrigExpseg will sends a trigger signal at the end of the playback.
    User can retreive the trigger streams by calling obj['trig'].
    Useful to synchronize other processes. 

    The out() method is bypassed. TrigExpseg's signal can not be sent
    to audio outs.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> m = Metro(time=0.5, poly=2).play()
    >>> pit = TrigExpseg(m, [(0,1000),(.25,1300),(.5,1000),(1,1000)])
    >>> a = Sine(pit, mul=.2).out()

    """
    def __init__(self, input, list, exp=10, inverse=True, mul=1, add=0):
        PyoObject.__init__(self)
        if type(list) != ListType:
            print >> sys.stderr, 'TypeError: "list" argument of %s must be a list of tuples.\n' % self.__class__.__name__
            exit()
        if type(list[0]) != TupleType:
            print >> sys.stderr, 'TypeError: "list" argument of %s must be a list of tuples.\n' % self.__class__.__name__
            exit()
        self._input = input
        self._list = list
        self._exp = exp
        self._inverse = inverse
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, exp, inverse, mul, add, lmax = convertArgsToLists(self._in_fader, exp, inverse, mul, add)
        self._base_objs = [TrigExpseg_base(wrap(in_fader,i), list, wrap(exp,i), wrap(inverse,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
        self._trig_objs = Dummy([TriggerDummy_base(obj) for obj in self._base_objs])

    def __dir__(self):
        return ['input', 'list', 'exp', 'inverse', 'mul', 'add']

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setList(self, x):
        """
        Replace the `list` attribute.
        
        Parameters:

        x : list of tuples
            new `list` attribute.
        
        """
        self._list = x
        [obj.setList(x) for i, obj in enumerate(self._base_objs)]

    def setExp(self, x):
        """
        Replace the `exp` attribute.

        Parameters:

        x : float
            new `exp` attribute.

        """
        self._exp = x
        x, lmax = convertArgsToLists(x)
        [obj.setExp(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setInverse(self, x):
        """
        Replace the `inverse` attribute.

        Parameters:

        x : boolean
            new `inverse` attribute.

        """
        self._inverse = x
        x, lmax = convertArgsToLists(x)
        [obj.setInverse(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def replace(self, x):
        """
        Alias for `setList` method.

        Parameters:

        x : list of tuples
            new `list` attribute.

        """
        self.setList(x)

    def getPoints(self):
        return self._list

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    def graph(self, xlen=None, yrange=None, title=None, wxnoserver=False):
        """
        Opens a grapher window to control the shape of the envelope.

        When editing the grapher with the mouse, the new set of points
        will be send to the object on mouse up. 

        Ctrl+C with focus on the grapher will copy the list of points to the 
        clipboard, giving an easy way to insert the new shape in a script.

        Parameters:

        xlen : float, optional
            Set the maximum value of the X axis of the graph. If None, the
            maximum value is retrieve from the current list of points.
            Defaults to None.
        yrange : tuple, optional
            Set the min and max values of the Y axis of the graph. If
            None, min and max are retrieve from the current list of points.
            Defaults to None.
        title : string, optional
            Title of the window. If none is provided, the name of the 
            class is used.
        wxnoserver : boolean, optional
            With wxPython graphical toolkit, if True, tells the 
            interpreter that there will be no server window and not 
            to wait for it before showing the controller window. 
            Defaults to False.

        """
        if xlen == None:
            xlen = float(self._list[-1][0])
        else:
            xlen = float(xlen)
        if yrange == None:
            ymin = float(min([x[1] for x in self._list]))
            ymax = float(max([x[1] for x in self._list]))
            if ymin == ymax:
                yrange = (0, ymax)
            else:
                yrange = (ymin, ymax)
        createGraphWindow(self, 2, xlen, yrange, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def list(self): return self._list
    @list.setter
    def list(self, x): self.setList(x)
    @property
    def exp(self): return self._exp
    @exp.setter
    def exp(self, x): self.setExp(x)
    @property
    def inverse(self): return self._inverse
    @inverse.setter
    def inverse(self, x): self.setInverse(x)

class TrigXnoise(PyoObject):
    """
    Triggered X-class pseudo-random generator.

    Xnoise implements a few of the most common noise distributions. 
    A new value is generated each time the object receive a trigger 
    in input. Each distribution generates values in the range 0 and 1.

    Parentclass: PyoObject

    Notes:

    Available distributions are:
        - uniform
        - linear minimum
        - linear maximum
        - triangular
        - exponential minimum
        - exponential maximum
        - double (bi)exponential
        - cauchy
        - weibull
        - gaussian
        - poisson
        - walker (drunk)
        - loopseg (drunk with looped segments)

    Depending on the distribution, `x1` and `x2` parameters are applied
    as follow (names as string, or associated number can be used as `dist`
    parameter):
        0 - uniform
            no parameter
        1 - linear_min 
            no parameter
        2 - linear_max
            no parameter
        3 - triangle
            no parameter
        4 - expon_min
            x1 : slope {0 = no slope -> 10 = sharp slope}
        5 - expon_max    
            x1 : slope {0 = no slope -> 10 = sharp slope}
        6 - biexpon
            x1 : bandwidth {0 = huge bandwidth -> 10 = narrow bandwidth}
        7 - cauchy
            x1 : bandwidth {0 = narrow bandwidth -> 10 = huge bandwidth}
        8 - weibull
            x1 : mean location {0 -> 1}
            x2 : shape {0.5 = linear min, 1.5 = expon min, 3.5 = gaussian}
        9 - gaussian
            x1 : mean location {0 -> 1}
            x2 : bandwidth {0 =  narrow bandwidth -> 10 = huge bandwidth}
        10 - poisson
            x1 : gravity center {0 = low values -> 10 = high values}
            x2 : compress/expand range {0.1 = full compress -> 4 full expand}
        11 - walker
            x1 : maximum value {0.1 -> 1}
            x2 - maximum step {0.1 -> 1}
        12 - loopseg 
            x1 : maximum value {0.1 -> 1}
            x2 - maximum step {0.1 -> 1}

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    dist : string or int, optional
        Distribution type. Defaults to 0.
    x1 : float or PyoObject, optional
        First parameter. Defaults to 0.5.
    x2 : float or PyoObject, optional
        Second parameter. Defaults to 0.5.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setDist(x) : Replace the `dist` attribute.
    setX1(x) : Replace the `x1` attribute.
    setX2(x) : Replace the `x2` attribute.

    Attributes:

    input : PyoObject. Audio trigger signal.
    dist : string or int. Distribution type.
    x1 : float or PyoObject. First parameter.
    x2 : float or PyoObject. Second parameter.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> wav = SquareTable()
    >>> env = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> met = Metro(.125, 12).play()
    >>> amp = TrigEnv(met, table=env, mul=.2)
    >>> pit = TrigXnoise(met, dist=4, x1=10, mul=1000, add=200)
    >>> a = Osc(table=wav, freq=pit, mul=amp).out()

    """
    def __init__(self, input, dist=0, x1=0.5, x2=0.5, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._dist = dist
        self._x1 = x1
        self._x2 = x2
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, dist, x1, x2, mul, add, lmax = convertArgsToLists(self._in_fader, dist, x1, x2, mul, add)
        for i, t in enumerate(dist):
            if type(t) == StringType: dist[i] = XNOISE_DICT.get(t, 0)
        self._base_objs = [TrigXnoise_base(wrap(in_fader,i), wrap(dist,i), wrap(x1,i), wrap(x2,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'dist', 'x1', 'x2', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setDist(self, x):
        """
        Replace the `dist` attribute.

        Parameters:

        x : int
            new `dist` attribute.

        """
        self._dist = x
        x, lmax = convertArgsToLists(x)
        for i, t in enumerate(x):
            if type(t) == StringType: x[i] = XNOISE_DICT.get(t, 0)
        [obj.setType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setX1(self, x):
        """
        Replace the `x1` attribute.

        Parameters:

        x : float or PyoObject
            new `x1` attribute.

        """
        self._x1 = x
        x, lmax = convertArgsToLists(x)
        [obj.setX1(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setX2(self, x):
        """
        Replace the `x2` attribute.

        Parameters:

        x : float or PyoObject
            new `x2` attribute.

        """
        self._x2= x
        x, lmax = convertArgsToLists(x)
        [obj.setX2(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def dist(self): return self._dist
    @dist.setter
    def dist(self, x): self.setDist(x)
    @property
    def x1(self): return self._x1
    @x1.setter
    def x1(self, x): self.setX1(x)
    @property
    def x2(self): return self._x2
    @x2.setter
    def x2(self, x): self.setX2(x)

class TrigXnoiseMidi(PyoObject):
    """
    Triggered X-class midi notes pseudo-random generator.

    Xnoise implements a few of the most common noise distributions. 
    A new value is generated each time the object receive a trigger 
    in input. Each distribution generates integer values in the range 
    defined with `mrange` parameter and output can be scaled on midi 
    notes, hertz or transposition factor.

    Parentclass: PyoObject

    Notes:

    Available distributions are:
        - uniform
        - linear minimum
        - linear maximum
        - triangular
        - exponential minimum
        - exponential maximum
        - double (bi)exponential
        - cauchy
        - weibull
        - gaussian
        - poisson
        - walker (drunk)
        - loopseg (drunk with looped segments)

    Depending on the distribution, `x1` and `x2` parameters are applied
    as follow (names as string, or associated number can be used as `dist`
    parameter):
        0 - uniform
            no parameter
        1 - linear_min 
            no parameter
        2 - linear_max
            no parameter
        3 - triangle
            no parameter
        4 - expon_min
            x1 : slope {0 = no slope -> 10 = sharp slope}
        5 - expon_max    
            x1 : slope {0 = no slope -> 10 = sharp slope}
        6 - biexpon
            x1 : bandwidth {0 = huge bandwidth -> 10 = narrow bandwidth}
        7 - cauchy
            x1 : bandwidth {0 = narrow bandwidth -> 10 = huge bandwidth}
        8 - weibull
            x1 : mean location {0 -> 1}
            x2 : shape {0.5 = linear min, 1.5 = expon min, 3.5 = gaussian}
        9 - gaussian
            x1 : mean location {0 -> 1}
            x2 : bandwidth {0 =  narrow bandwidth -> 10 = huge bandwidth}
        10 - poisson
            x1 : gravity center {0 = low values -> 10 = high values}
            x2 : compress/expand range {0.1 = full compress -> 4 full expand}
        11 - walker
            x1 : maximum value {0.1 -> 1}
            x2 - maximum step {0.1 -> 1}
        12 - loopseg 
            x1 : maximum value {0.1 -> 1}
            x2 - maximum step {0.1 -> 1}

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    dist : string of int, optional
        Distribution type. Defaults to 0.
    x1 : float or PyoObject, optional
        First parameter. Defaults to 0.5.
    x2 : float or PyoObject, optional
        Second parameter. Defaults to 0.5.
    scale : int {0, 1, 2}, optional
        Output format. 0 = MIDI, 1 = Hertz, 2 = transposition factor. 
        In the transposition mode, the central key (the key where there 
        is no transposition) is (`minrange` + `maxrange`) / 2. Defaults
        to 0.
    mrange : tuple of int, optional
        Minimum and maximum possible values, in Midi notes. Available
        only at initialization time. Defaults to (0, 127).

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setDist(x) : Replace the `dist` attribute.
    setX1(x) : Replace the `x1` attribute.
    setX2(x) : Replace the `x2` attribute.
    setScale(x) : Replace the `scale` attribute.
    setRange(x, y) : Changes min and max range values and centralkey.

    Attributes:

    input : PyoObject. Audio trigger signal.
    dist : string or int. Distribution type.
    x1 : float or PyoObject. First parameter.
    x2 : float or PyoObject. Second parameter.
    scale : int. Output format.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> wav = SquareTable()
    >>> env = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> met = Metro(.125, 12).play()
    >>> amp = TrigEnv(met, table=env, mul=.2)
    >>> pit = TrigXnoiseMidi(met, dist=4, x1=10, scale=1, mrange=(48,84))
    >>> a = Osc(table=wav, freq=pit, mul=amp).out()

    """
    def __init__(self, input, dist=0, x1=0.5, x2=0.5, scale=0, mrange=(0,127), mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._dist = dist
        self._x1 = x1
        self._x2 = x2
        self._scale = scale
        self._mrange = mrange        
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, dist, x1, x2, scale, mrange, mul, add, lmax = convertArgsToLists(self._in_fader, dist, x1, x2, scale, mrange, mul, add)
        for i, t in enumerate(dist):
            if type(t) == StringType: dist[i] = XNOISE_DICT.get(t, 0)
        self._base_objs = [TrigXnoiseMidi_base(wrap(in_fader,i), wrap(dist,i), wrap(x1,i), wrap(x2,i), wrap(scale,i), wrap(mrange,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'dist', 'x1', 'x2', 'scale', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setDist(self, x):
        """
        Replace the `dist` attribute.

        Parameters:

        x : int
            new `dist` attribute.

        """
        self._dist = x
        x, lmax = convertArgsToLists(x)
        for i, t in enumerate(x):
            if type(t) == StringType: x[i] = XNOISE_DICT.get(t, 0)
        [obj.setType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setScale(self, x):
        """
        Replace the `scale` attribute.

        Possible values are: 
            0 -> Midi notes
            1 -> Hertz
            2 -> transposition factor 
                 (centralkey is (`minrange` + `maxrange`) / 2

        Parameters:

        x : int {0, 1, 2}
            new `scale` attribute.

        """
        self._scale = x
        x, lmax = convertArgsToLists(x)
        [obj.setScale(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setRange(self, mini, maxi):
        """
        Replace the `mrange` attribute.

        Parameters:

        mini : int
            minimum output midi range.
        maxi : int
            maximum output midi range.

        """
        self._mrange = (mini, maxi)
        mini, maxi, lmax = convertArgsToLists(mini, maxi)
        [obj.setRange(wrap(mini,i), wrap(maxi,i)) for i, obj in enumerate(self._base_objs)]

    def setX1(self, x):
        """
        Replace the `x1` attribute.

        Parameters:

        x : float or PyoObject
            new `x1` attribute.

        """
        self._x1 = x
        x, lmax = convertArgsToLists(x)
        [obj.setX1(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setX2(self, x):
        """
        Replace the `x2` attribute.

        Parameters:

        x : float or PyoObject
            new `x2` attribute.

        """
        self._x2= x
        x, lmax = convertArgsToLists(x)
        [obj.setX2(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def dist(self): return self._dist
    @dist.setter
    def dist(self, x): self.setDist(x)
    @property
    def scale(self): return self._scale
    @scale.setter
    def scale(self, x): self.setScale(x)
    @property
    def x1(self): return self._x1
    @x1.setter
    def x1(self, x): self.setX1(x)
    @property
    def x2(self): return self._x2
    @x2.setter
    def x2(self, x): self.setX2(x)

class Counter(PyoObject):
    """
    Integer count generator.

    Counter keeps track of all triggers received, outputs the current 
    count constrained within `min` and `max` range, and can be set to 
    count up, down, or up-and-down.


    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    min : int, optional
        Minimum value of the count, included in the count. Defaults to 0.
    max : int, optional
        Maximum value of the count. excluded of the count. 
        The counter will count up to max - 1. Defaults to 100.
    dir : int {0, 1, 2}, optional
        Direction of the count. Three possible values:
            0 : up
            1 : down
            2 : up-and-down
        Defaults to 0.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setMin(x) : Replace the `min` attribute.
    setMax(x) : Replace the `max` attribute.
    setDir(x) : Replace the `dir` attribute.
    reset(value) : Reset the current count.

    Attributes:

    input : PyoObject. Audio trigger signal.
    min : int. Minimum value.
    max : int. Maximum value.
    dir : int. Direction of the count.

    Notes:

    The out() method is bypassed. Counter's signal can not be sent 
    to audio outs.

    See also: Select

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> m = Metro(.125).play()
    >>> c = Counter(m, min=3, max=8, dir=2, mul=100)
    >>> a = Sine(freq=c, mul=.2).mix(2).out()

    """
    def __init__(self, input, min=0, max=100, dir=0, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._min = min
        self._max = max
        self._dir = dir
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, min, max, dir, mul, add, lmax = convertArgsToLists(self._in_fader, min, max, dir, mul, add)
        self._base_objs = [Counter_base(wrap(in_fader,i), wrap(min,i), wrap(max,i), wrap(dir,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'min', 'max', 'dir', 'mul', 'add']

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setMin(self, x):
        """
        Replace the `min` attribute.
        
        Parameters:

        x : int
            new `min` attribute.
        
        """
        self._min = x
        x, lmax = convertArgsToLists(x)
        [obj.setMin(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setMax(self, x):
        """
        Replace the `max` attribute.
        
        Parameters:

        x : int
            new `max` attribute.
        
        """
        self._max = x
        x, lmax = convertArgsToLists(x)
        [obj.setMax(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setDir(self, x):
        """
        Replace the `dir` attribute.
        
        Parameters:

        x : int {0, 1, 2}
            new `dir` attribute.
        
        """
        self._dir = x
        x, lmax = convertArgsToLists(x)
        [obj.setDir(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def reset(self, value=None):
        """
        Reset the current count of the counter. If `value` is None, the counter
        resets to the beginning of the count.

        Parameters:

        value : int, optional
            Value where to reset the count. Defaults to None.

        """
        value, lmax = convertArgsToLists(value)
        [obj.reset(wrap(value,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def min(self): return self._min
    @min.setter
    def min(self, x): self.setMin(x)
    @property
    def max(self): return self._max
    @max.setter
    def max(self, x): self.setMax(x)
    @property
    def dir(self): return self._dir
    @dir.setter
    def dir(self, x): self.setDir(x)

class Select(PyoObject):
    """
    Sends trigger on matching integer values.

    Select takes in input an audio signal containing integer numbers
    and sends a trigger when the input matches `value` parameter. This
    object is especially designed to be used with Counter object.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal. Must contains integer numbers.
    value : int, optional
        Value to be matched to send a trigger. Defaults to 0.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setValue(x) : Replace the `value` attribute.

    Attributes:

    input : PyoObject. Audio signal.
    value : int. Matching value.

    Notes:

    The out() method is bypassed. Select's signal can not be sent 
    to audio outs.

    See also: Counter

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> env = HannTable()
    >>> m = Metro(.125, poly=2).play()
    >>> te = TrigEnv(m, table=env, dur=.2, mul=.2)
    >>> c = Counter(m, min=0, max=4)
    >>> se = Select(c, 0)
    >>> tr = TrigRand(se, 400, 600)
    >>> a = Sine(freq=tr, mul=te).out()

    """
    def __init__(self, input, value=0, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._value = value
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, value, mul, add, lmax = convertArgsToLists(self._in_fader, value, mul, add)
        self._base_objs = [Select_base(wrap(in_fader,i), wrap(value,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'value', 'mul', 'add']

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setValue(self, x):
        """
        Replace the `value` attribute.
        
        Parameters:

        x : int
            new `value` attribute.
        
        """
        self._value = x
        x, lmax = convertArgsToLists(x)
        [obj.setValue(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def value(self): return self._value
    @value.setter
    def value(self, x): self.setValue(x)

class Change(PyoObject):
    """
    Sends trigger that informs when input value has changed.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal. Must contains integer numbers.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.

    Attributes:

    input : PyoObject. Audio signal.

    Notes:

    The out() method is bypassed. Change's signal can not be sent 
    to audio outs.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> a = XnoiseMidi(dist="loopseg", freq=[2, 3], x1=1, scale=1, mrange=(60,73))
    >>> b = Change(a)
    >>> amp = TrigEnv(b, table=t, dur=[.5,.333], mul=.3)
    >>> out = SineLoop(freq=a, feedback=.05, mul=amp).out()

    """
    def __init__(self, input, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add)
        self._base_objs = [Change_base(wrap(in_fader,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'mul', 'add']

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)

class Thresh(PyoObject):
    """
    Informs when a signal crosses a threshold.
    
    Thresh sends a trigger when a signal crosses a threshold. The `dir` 
    parameter can be used to set the crossing mode, down-up, up-down, or 
    both.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    threshold : float or PyoObject, optional
        Threshold value. Defaults to 0.
    dir : int {0, 1, 2}, optional
        There are three modes of using Thresh:
            dir = 0 : down-up
                sends a trigger when current value is higher than the
                threshold, while old value was equal to or lower than 
                the threshold.
            dir = 1 : up-down
                sends a trigger when current value is lower than the
                threshold, while old value was equal to or higher than 
                the threshold.
            dir = 2 : both direction
                sends a trigger in both the two previous cases.
        Defaults to 0.    
    
    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setThreshold(x) : Replace the `threshold` attribute.
    setDir(x) : Replace the `dir` attribute.

    Attributes:
    
    input : PyoObject. Audio signal.
    threshold : float or PyoObject. Threshold value.
    dir : int. User mode.

    Notes:

    The out() method is bypassed. Thresh's signal can not be sent 
    to audio outs.

    Examples:
    
    >>> s = Server().boot()
    >>> s.start()
    >>> a = Phasor(1)
    >>> b = Thresh(a, threshold=[0.25, 0.5, 0.66], dir=0)
    >>> t = LinTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> env = TrigEnv(b, table=t, dur=.5, mul=.3)
    >>> sine = Sine(freq=[500,600,700], mul=env).out()
    
    """
    def __init__(self, input, threshold=0., dir=0, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._mul = mul
        self._add = add
        self._threshold = threshold
        self._dir = dir
        self._in_fader = InputFader(input)
        in_fader, threshold, dir, mul, add, lmax = convertArgsToLists(self._in_fader, threshold, dir, mul, add)
        self._base_objs = [Thresh_base(wrap(in_fader,i), wrap(threshold,i), wrap(dir,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'threshold', 'dir', 'mul', 'add']

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.
        
        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setThreshold(self, x):
        """
        Replace the `threshold` attribute.
        
        Parameters:

        x : float or PyoObject
            new `threshold` attribute.
        
        """
        self._threshold = x
        x, lmax = convertArgsToLists(x)
        [obj.setThreshold(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setDir(self, x):
        """
        Replace the `dir` attribute.
        
        Parameters:

        x : int {0, 1, 2}
            new `dir` attribute.
        
        """
        self._dir = x
        x, lmax = convertArgsToLists(x)
        [obj.setDir(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def threshold(self): return self._threshold
    @threshold.setter
    def threshold(self, x): self.setThreshold(x)
    @property
    def dir(self): return self._dir
    @dir.setter
    def dir(self, x): self.setDir(x)

class Percent(PyoObject):
    """
    Lets pass a certain percentage of the input triggers.

    Percent looks at the triggers received in `input` and
    lets them pass `percent` of the time.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    percent : float or PyoObject, optional
        How much percentage of triggers to let pass, 
        between 0 and 100. Defaults to 50.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setPercent(x) : Replace the `percent` attribute.

    Attributes:

    input : PyoObject. Audio signal.
    percent : float or PyoObject. Percentage value.

    Notes:

    The out() method is bypassed. Percent's signal can not 
    be sent to audio outs.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(time=.125, poly=2).play()
    >>> trig = Percent(met, percent=50)
    >>> amp = TrigEnv(trig, table=t, dur=.25, mul=.3)
    >>> fr = TrigRand(trig, min=400, max=1000)
    >>> freq = Port(fr, risetime=0.001, falltime=0.001)
    >>> a = Sine(freq=freq, mul=amp).out()

    """
    def __init__(self, input, percent=50., mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._percent = percent
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, percent, mul, add, lmax = convertArgsToLists(self._in_fader, percent, mul, add)
        self._base_objs = [Percent_base(wrap(in_fader,i), wrap(percent,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'percent', 'mul', 'add']

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setPercent(self, x):
        """
        Replace the `percent` attribute.

        Parameters:

        x : float or PyoObject
            new `percent` attribute.

        """
        self._percent = x
        x, lmax = convertArgsToLists(x)
        [obj.setPercent(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0., 100., 'lin', 'percent', self._percent)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def percent(self): return self._percent
    @percent.setter
    def percent(self, x): self.setPercent(x)

class Timer(PyoObject):
    """
    Reports elapsed time between two trigs.

    A trigger in `input2` signal starts an internal timer. The next trigger 
    in `input` signal stops it and reports the elapsed time between the two 
    triggers. Useful for filtering triggers that are too close to each other. 

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Trigger signal. Stops the timer and reports elapsed time.
    input2 : PyoObject
        Trigger signal. Starts the timer if not already started.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setInput2(x, fadetime) : Replace the `input2` attribute.

    Attributes:

    input : PyoObject. Timer stop signal.
    input2 : PyoObject. Timer start signal.

    Notes:

    The `input` signal is evaluated before the `input2` signal, so it's
    safe to stop and start the timer with the same trigger signal.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> cl = Cloud(density=20, poly=2).play()
    >>> ti = Timer(cl, cl)
    >>> # Minimum waiting time before a new trig
    >>> cp = Compare(ti, comp=.05, mode=">")
    >>> trig = cl * cp
    >>> amp = TrigEnv(trig, table=HannTable(), dur=.05, mul=.25)
    >>> freq = TrigChoice(trig, choice=[100,150,200,250,300,350,400])
    >>> a = LFO(freq=freq, type=2, mul=amp).out()

    """
    def __init__(self, input, input2, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._input2 = input2
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        self._in_fader2 = InputFader(input2)
        in_fader, in_fader2, mul, add, lmax = convertArgsToLists(self._in_fader, self._in_fader2, mul, add)
        self._base_objs = [Timer_base(wrap(in_fader,i), wrap(in_fader2,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'input2', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Default to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setInput2(self, x, fadetime=0.05):
        """
        Replace the `input2` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Default to 0.05.

        """
        self._input2 = x
        self._in_fader2.setInput(x, fadetime)

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Timer stop signal.""" 
        return self._input
    @input.setter
    def input(self, x): self.setInput(x)

    @property
    def input2(self):
        """PyoObject. Timer start signal.""" 
        return self._input2
    @input2.setter
    def input2(self, x): self.setInput2(x)

class Iter(PyoObject):
    """
    Triggers iterate over a list of values.

    Iter loops over a list of user-defined values. When a trigger is received
    in `input`, Iter moves up to the next value in the list, with wrap-around. 

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Audio signal sending triggers.
    choice : list of floats
        Sequence of values over which to iterate.
    init : float, optional
        Initial value. Available at initialization time only. 
        Defaults to 0.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setChoice(x) : Replace the `choice` attribute.
    reset(x) : Resets the current count.

    Attributes:

    input : PyoObject. Audio trigger signal.
    choice : list of floats. Possible values.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> l1 = [300, 350, 400, 450, 500, 550]
    >>> l2 = [300, 350, 450, 500, 550]
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(time=.125, poly=2).play()
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> it = Iter(met, choice=[l1, l2])
    >>> si = Sine(freq=it, mul=amp).out()

    """
    def __init__(self, input, choice, init=0., mul=1, add=0):
        PyoObject.__init__(self)
        if type(choice) != ListType:
            print >> sys.stderr, 'TypeError: "choice" argument of %s must be a list.\n' % self.__class__.__name__
            exit()
        self._input = input
        self._choice = choice
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, init, mul, add, lmax = convertArgsToLists(self._in_fader, init, mul, add)
        if type(choice[0]) != ListType:
            self._base_objs = [Iter_base(wrap(in_fader,i), choice, wrap(init,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
        else:
            choicelen = len(choice)
            lmax = max(choicelen, lmax)
            self._base_objs = [Iter_base(wrap(in_fader,i), wrap(choice,i), wrap(init,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'choice', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Defaults to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setChoice(self, x):
        """
        Replace the `choice` attribute.

        Parameters:

        x : list of floats
            new `choice` attribute.

        """
        self._choice = x
        if type(x[0]) != ListType:
            [obj.setChoice(self._choice) for i, obj in enumerate(self._base_objs)]
        else:
            [obj.setChoice(wrap(self._choice,i)) for i, obj in enumerate(self._base_objs)]

    def reset(self, x=0):
        """
        Resets the current count.
        
        Parameters:
        
        x : int, optional
            Value where to reset the count. Defaults to 0.
        
        """
        [obj.reset(x) for obj in self._base_objs]
        
    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def choice(self): return self._choice
    @choice.setter
    def choice(self, x): self.setChoice(x)

class Count(PyoObject):
    """
    Counts integers at audio rate.

    Count generates a signal increasing by 1 each sample when it receives a 
    trigger. It can be used to do sample playback using TableIndex. 

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Trigger signal. Start or Restart the count.
    min : int, optional
        Minimum value of the count, included in the count. Defaults to 0.
    max : int, optional
        Maximum value of the count. excluded of the count. A value of 0 
        eliminates the maximum, and the count continues increasing without 
        resetting. Defaults to 0.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setMin(x) : Replace the `min` attribute.
    setMax(x) : Replace the `max` attribute.

    Attributes:

    input : PyoObject. Trigger signal. Start/Restart the count.
    min : int. Minimum value.
    max : int. Maximum value.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> t = SndTable(SNDS_PATH+'/accord.aif')
    >>> ind = Count(Trig().play(), [0,100], t.getSize())
    >>> read = TableIndex(t, ind).out()

    """
    def __init__(self, input, min=0, max=0, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._min = min
        self._max = max
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        in_fader, min, max, mul, add, lmax = convertArgsToLists(self._in_fader, min, max, mul, add)
        self._base_objs = [Count_base(wrap(in_fader,i), wrap(min,i), wrap(max,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'min', 'max', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        Parameters:

        x : PyoObject
            New input signal.
        fadetime : float, optional
            Crossfade time between old and new input. Default to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setMin(self, x):
        """
        Replace the `min` attribute.

        Parameters:

        x : int
            new `min` attribute.

        """
        self._min = x
        x, lmax = convertArgsToLists(x)
        [obj.setMin(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def setMax(self, x):
        """
        Replace the `max` attribute.

        Parameters:

        x : int
            new `max` attribute.

        """
        self._max = x
        x, lmax = convertArgsToLists(x)
        [obj.setMax(wrap(x,i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)
    @property
    def min(self): return self._min
    @min.setter
    def min(self, x): self.setMin(x)
    @property
    def max(self): return self._max
    @max.setter
    def max(self, x): self.setMax(x)

class NextTrig(PyoObject):
    """
    A trigger in the second stream opens a gate only for the next one in the first stream.

    When the gate is opened by a trigger in `input2` signal, the next trigger 
    in `input` signal is allowed to pass and automatically closes the gate.

    Parentclass: PyoObject

    Parameters:

    input : PyoObject
        Trigger signal. Trigger stream waiting for the gate to be opened.
    input2 : PyoObject
        Trigger signal. Trigger stream opening the gate.

    Methods:

    setInput(x, fadetime) : Replace the `input` attribute.
    setInput2(x, fadetime) : Replace the `input2` attribute.

    Attributes:

    input : PyoObject. Incoming trigger stream signal.
    input2 : PyoObject. Trigger stream opening the gate.

    Notes:

    The `input` signal is evaluated before the `input2` signal, so it's
    safe to send triggers in both inputs at the same time and wait for the
    next one.

    Examples:

    >>> s = Server().boot()
    >>> s.start()
    >>> mid = Urn(max=4, freq=4, add=60)
    >>> sigL = SineLoop(freq=MToF(mid), feedback=.08, mul=0.3).out()
    >>> first = NextTrig(Change(mid), mid["trig"])
    >>> amp = TrigExpseg(first, [(0,0),(.01,.25),(1,0)])
    >>> sigR = SineLoop(midiToHz(84), feedback=0.05, mul=amp).out(1)

    """
    def __init__(self, input, input2, mul=1, add=0):
        PyoObject.__init__(self)
        self._input = input
        self._input2 = input2
        self._mul = mul
        self._add = add
        self._in_fader = InputFader(input)
        self._in_fader2 = InputFader(input2)
        in_fader, in_fader2, mul, add, lmax = convertArgsToLists(self._in_fader, self._in_fader2, mul, add)
        self._base_objs = [NextTrig_base(wrap(in_fader,i), wrap(in_fader2,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    def __dir__(self):
        return ['input', 'input2', 'mul', 'add']

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Default to 0.05.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setInput2(self, x, fadetime=0.05):
        """
        Replace the `input2` attribute.

        Parameters:

        x : PyoObject
            New signal to process.
        fadetime : float, optional
            Crossfade time between old and new input. Default to 0.05.

        """
        self._input2 = x
        self._in_fader2.setInput(x, fadetime)

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = []
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self): return self._input
    @input.setter
    def input(self, x): self.setInput(x)

    @property
    def input2(self): return self._input2
    @input2.setter
    def input2(self, x): self.setInput2(x)
